import 'package:flutter/material.dart';
import 'layer.dart';

class LineLayer extends Layer {
  Offset start, end;
  Offset? _dragStart;
  String? _dragType;
  bool _dragging = false;
  LineLayer(
    this.start,
    this.end,
  );

  Offset handleOffset = const Offset(0, 60);
  Offset get controlStart => start + handleOffset;
  Offset get controlEnd => end + handleOffset;

  @override
  bool hitTest(Offset p) {
    if ((p - controlStart).distance <= hitRadius) return true;
    if ((p - controlEnd).distance <= hitRadius) return true;
    final ab = end - start, ap = p - start;
    final t = (ap.dx * ab.dx + ap.dy * ab.dy) / ab.distanceSquared;
    final tt = t.clamp(0.0, 1.0);
    final proj = start + ab * tt;
    return (p - proj).distance <= hitRadius;
  }

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = selected ? Colors.orange : Colors.white
      ..strokeWidth = 1
      ..style = PaintingStyle.stroke;

    // 虚线
    const dashW = 5.0, dashS = 3.0, pad = 8.0;
    final total = (end - start).distance;
    if (total > pad * 2) {
      final dir = (end - start) / total;
      double cur = pad;
      final drawable = total - pad * 2;
      final cnt = (drawable / (dashW + dashS)).floor();
      for (int i = 0; i < cnt; i++) {
        final a = start + dir * cur;
        canvas.drawLine(a, a + dir * dashW, paint);
        cur += dashW + dashS;
      }
    }

    // plus
    void drawPlus(Offset c) {
      final pp = Paint()
        ..color = (_dragging || selected) ? Colors.orange : Colors.white
        ..strokeWidth = 2
        ..strokeCap = StrokeCap.round;
      const arm = 8.0, gap = 2.0;
      canvas.save();
      canvas.translate(c.dx, c.dy);
      canvas.drawLine(const Offset(0, -arm), const Offset(0, -gap), pp);
      canvas.drawLine(const Offset(0, gap), const Offset(0, arm), pp);
      canvas.drawLine(const Offset(-arm, 0), const Offset(-gap, 0), pp);
      canvas.drawLine(const Offset(gap, 0), const Offset(arm, 0), pp);
      canvas.restore();
    }

    drawPlus(start);
    drawPlus(end);
  }

  @override
  void onPanStart(Offset p, Size b) {
    if (!selected) return;
    _dragStart = p;
    _dragging = true;

    // 点击 start 十字中心
    if ((p - start).distance <= hitRadius) {
      _dragType = 'start';
    }
    // 点击 end 十字中心
    else if ((p - end).distance <= hitRadius) {
      _dragType = 'end';
    }
    // 点击控制点位置
    else if ((p - controlStart).distance <= hitRadius) {
      _dragType = 'start';
      start = controlStart - handleOffset;
    } else if ((p - controlEnd).distance <= hitRadius) {
      _dragType = 'end';
      end = controlEnd - handleOffset;
    } else {
      _dragType = null;
      _dragging = false;
      _dragStart = null;
    }
  }

  @override
  void onPanUpdate(Offset p, Size boundary) {
    if (!_dragging || _dragStart == null || _dragType == null) return;
    final delta = p - _dragStart!;

    if (_dragType == 'start') {
      final newStart = start + delta;
      start = _offsetArea(newStart, boundary);
    } else if (_dragType == 'end') {
      final newEnd = end + delta;
      end = _offsetArea(newEnd, boundary);
    }

    _dragStart = p;
  }

  _offsetArea(Offset newOffset, Size boundary) {
    return Offset(
      newOffset.dx.clamp(safeSpace, boundary.width - safeSpace),
      newOffset.dy.clamp(safeSpace, boundary.height - safeSpace),
    );
  }

  @override
  void onPanEnd(Size boundary) {
    _dragging = false;
    _dragType = null;
    selected = false;
  }

  @override
  double getMetric() {
    return (end - start).distance;
  }
}
